/* 
 * File:   ClimbingGame.cpp
 * Author: aljosa
 * 
 * Created on April 28, 2010, 8:06 PM
 */

#include "VirtualScriptExample.h"

// Subsystems
#include "../RenderingSystem.h"
#include "../World2D.h"


#include "../ClimbingGame/RectBody.h"
#include "../ClimbingGame/CircleBody.h"

#include <cstdlib>
#include <ctime>
#include <queue>

#include "../EventSystem.h"
#include "../TranslateEvent.h"
#include "../MathUtil.h"

#include "../ResourceManager.h"

#include <iostream>

using namespace std;
using namespace xEngine::Renderer;
using namespace xEngine::CoreSystem::Events;

namespace ClimbingGame
{
    ClimbingGame::ClimbingGame() {
       // RANDOM_SEED()
        srand(time(NULL));
    }

    ClimbingGame::~ClimbingGame() {
    }

    // Initialization, destruction
    bool ClimbingGame::init() {
        // Create game world
        this->world = new World2D(); // Create world object
        world->init();
        
        ( (World2D*)world )->create(0.0f, -10.0f, 28, 23); // Create world
        this->setWorld( this->world ); // Set pointer


        // Parse script
        parser.compileFile("data/test.xs", this->world->getHash());
        cout<<parser.getStatus()<<endl;

        return true;
    }

    void ClimbingGame::shutDown() {
        // Clean world
        if ( this->world != NULL ) {
            this->world->shutDown();
            delete world;
            world = NULL;
        }
    }

    // Game loop related
    void ClimbingGame::draw(double deltaTime) {
       this->world->draw(deltaTime);
    }

    void ClimbingGame::update(double deltaTime) {
        // Process events
        //queue<Event*>  *qu = xEngine::CoreSystem::EventSystem::EventSystem::getInstance().getQueue(); // Get event queue
        EventSystem *events = &EventSystem::getInstance();


        // Loop thorugh events
        while ( events->numPending() > 0 ) {
            Event *event = events->popEvent();

            Box2DNode* node = NULL;

            // Handle events
            switch ( event->type )
            {
                case ROTATE_EVENT:
                {
                    node = (Box2DNode*) this->world->getObject(((RotateEvent*)event)->name);

                  //  node->body->SetAngularVelocity(((RotateEvent*)event)->angle);
                    node->bodyDef->angle = Deg2Rad ( ((RotateEvent*)event)->angle );
                    node->body->SetXForm( node->body->GetPosition(), ((RotateEvent*)event)->angle );

                    delete event; // EXPENSIVE, FIX!
                    break;
                }

                case TRANSLATE_EVENT:
                    node = (Box2DNode*) this->world->getObject(((TranslateEvent*)event)->name);
                    node->body->SetXForm( b2Vec2( ((TranslateEvent*)event)->pos.x, ((TranslateEvent*)event)->pos.y ), node->body->GetAngle() );
                    delete event;
                    break;

                case NEWB2O: {
                 //   cout<<"---- New B2 Obj EVENT!!!!111one ----"<<endl;
                 //   cout<< ((NewB2OEvent*)event)->objName << endl;

                    Box2DNode *node = NULL;


                    
                    switch ( ((NewB2OEvent*)event)->shape ) {
                        case RECT: {
                            node = new RectBody(((World2D*)this->world)->worldBox2D);

                          //  node->name = ((NewB2OEvent*)event)->objName;
                            node->init(
                            b2Vec2( ((NewB2OEvent*)event)->shapeData.w, ((NewB2OEvent*)event)->shapeData.h),
                            b2Vec2( ((NewB2OEvent*)event)->position.x, ((NewB2OEvent*)event)->position.y)
                            );

                            // Process Visual data
                            if ( ((NewB2OEvent*)event)->visual == COLOR ) {
                                ( (RectBody*)node )->fill = ((NewB2OEvent*)event)->visualData.fill;
                                ( (RectBody*)node )->border = ((NewB2OEvent*)event)->visualData.border;


                            }
                            else if ( ((NewB2OEvent*)event)->visual == TEXTURE ) {
                            //    cout<< "LOAD :" *(((NewB2OEvent*)event)->visualData.texture) << endl;
                                ( (RectBody*)node )->texId = ResourceManager::getInstance().getTexture( *(((NewB2OEvent*)event)->visualData.texture) )->texID;
                                ( (RectBody*)node )->texName = *(((NewB2OEvent*)event)->visualData.texture);
                                ( (RectBody*)node )->texRepeatX = ((NewB2OEvent*)event)->visualData.repeatX;
                                ( (RectBody*)node )->texRepeatY = ((NewB2OEvent*)event)->visualData.repeatY;
                            }

                            ( (RectBody*)node )->shapeDef->density = ((NewB2OEvent*)event)->materialData.density;
                            ( (RectBody*)node )->shapeDef->restitution = ((NewB2OEvent*)event)->materialData.restitution;

                           // ( (RectBody*)node )->name = ((NewB2OEvent*)event)->objName;
                            break;
                        }
                        case xEngine::CoreSystem::Events::CIRCLE: {
                         //   node->name = ((NewB2OEvent*)event)->objName;
                            
                            node = new CircleBody(((World2D*)this->world)->worldBox2D);
                            node->init(
                            ((NewB2OEvent*)event)->shapeData.radious,
                            b2Vec2( ((NewB2OEvent*)event)->position.x, ((NewB2OEvent*)event)->position.y)
                            );

                            ( (CircleBody*)node )->radious = ((NewB2OEvent*)event)->shapeData.radious;

                            // Process Visual data
                            if ( ((NewB2OEvent*)event)->visual == COLOR ) {
                                ( (CircleBody*)node )->fill = ((NewB2OEvent*)event)->visualData.fill;
                                ( (CircleBody*)node )->border = ((NewB2OEvent*)event)->visualData.border;
                            }
                            else if ( ((NewB2OEvent*)event)->visual == TEXTURE ) {
                            //    cout<< "LOAD :" *(((NewB2OEvent*)event)->visualData.texture) << endl;
                                ( (CircleBody*)node )->texId = ResourceManager::getInstance().getTexture( *(((NewB2OEvent*)event)->visualData.texture) )->texID;
                                ( (CircleBody*)node )->texName = *(((NewB2OEvent*)event)->visualData.texture);

                                ( (CircleBody*)node )->texRepeatX = ((NewB2OEvent*)event)->visualData.repeatX;
                                ( (CircleBody*)node )->texRepeatY = ((NewB2OEvent*)event)->visualData.repeatY;
                            }

                            ( (CircleBody*)node )->shapeDef->density = ((NewB2OEvent*)event)->materialData.density;
                            ( (CircleBody*)node )->shapeDef->restitution = ((NewB2OEvent*)event)->materialData.restitution;

                            break;
                        }
                    }

                    if ( node ) {
                        node->name = ((NewB2OEvent*)event)->objName;
                       // cout<< "OBJ NAME: "<<((NewB2OEvent*)event)->objName<<endl;
                        // Add node to the world
                        this->world->addChild(node);

                        bool dyn = ((NewB2OEvent*)event)->phyType == DYNAMIC ? true : false;
                        node->appear(dyn); // Make node appear
                    }

                    delete event; // FREE EVENT!
                    break;
                }

                default:
                    cout<<"Default: " << event->type << endl;
                   //       cout<< ((RotateEvent*)event)->name << "   " << ((RotateEvent*)event)->angle << endl;


            }
        }

        // Update world
        this->world->update(deltaTime);
    }

    void ClimbingGame::animate(double deltaTime) {
    }

    void ClimbingGame::handleInput() {
    }
}
